package com.thoughtworks.videorental.domain;

import static junit.framework.Assert.assertEquals;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;

import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import com.thoughtworks.datetime.Duration;
import com.thoughtworks.datetime.LocalDate;
import com.thoughtworks.datetime.Period;

public class CustomerTest {

	private static final String RESOURCES_PATH = "src/unit/resources";
	private static final Set<Rental> EMPTY_RENTALS = Collections.emptySet();

	private Customer customer;
	private Set<Rental> mixedRentals;
	private Set<Rental> rental;

	@Before
	public void setUp() {
		customer = new Customer("John Smith", "jsmith", "password");

		final Movie montyPython = new Movie("Monty Python and the Holy Grail", Movie.REGULAR);
		final Movie ran = new Movie("Ran", Movie.REGULAR);
		final Movie laConfidential = new Movie("LA Confidential", Movie.NEW_RELEASE);
		final Movie starTrek = new Movie("Star Trek 13.2", Movie.NEW_RELEASE);
		final Movie WallaceAndGromit = new Movie("Wallace and Gromit", Movie.CHILDRENS);

		mixedRentals = new LinkedHashSet<Rental>();
		
		mixedRentals.add(new Rental(customer, montyPython, Period.of(LocalDate.today(), Duration.ofDays(3))));
		mixedRentals.add(new Rental(customer, ran, Period.of(LocalDate.today(), Duration.ofDays(1))));
		mixedRentals.add(new Rental(customer, laConfidential, Period.of(LocalDate.today(), Duration.ofDays(2))));
		mixedRentals.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(1))));
		mixedRentals.add(new Rental(customer, WallaceAndGromit, Period.of(LocalDate.today(), Duration.ofDays(6))));
		
	}

	@Test
	public void testEmpty() throws Exception {
		String noRentalsStatement = 
			"Rental Record for John Smith\n"
			+ "Amount charged is $0.0\n" 
			+ "You have a new total of 0 frequent renter points";
		assertEquals(noRentalsStatement, customer.checkoutAndPrintStatement(EMPTY_RENTALS));
	}

	@Test
	public void testStatementFor1Transaction() throws Exception {
		String expected = 
			"Rental Record for John Smith\n" 
			+ "  Monty Python and the Holy Grail  -  $3.5\n"
			+ "  Ran  -  $2.0\n"
			+ "  LA Confidential  -  $3.0\n"
			+ "  Star Trek 13.2  -  $3.0\n"
			+ "  Wallace and Gromit  -  $6.0\n"
			+ "Amount charged is $17.5\n"
			+ "You have a new total of 6 frequent renter points"
			+ "\nHello John Smith, The New Release Price Movies were restricted to one day rental and amount charged will also reflect the same.";
		assertEquals(expected, customer.checkoutAndPrintStatement(mixedRentals));
	}
	
    @Test
    public void testPasswordValidated() throws Exception {
        assertThat(customer.isUsernameAndPasswordValid("jsmith", "incorrect"), is(false));
        assertThat(customer.isUsernameAndPasswordValid("incorrect", "password"), is(false));
        assertThat(customer.isUsernameAndPasswordValid("jsmith", "password"), is(true));
    }
    @Ignore
    @Test
	public void testCustomerForCurrentRenterPointsForASingleRegularMovie() throws Exception {
		String expected = 
			"Rental Record for John Smith\n" 
			+ "Your Current frequent renter points are 1";
		assertEquals(expected, customer.showCurrentRenterPoints(rental));
	}
    
    @Ignore
    @Test
	public void testCustomerForCurrentRenterPointsForMixedRental() throws Exception {
    	
    	final Movie starTrek = new Movie("Star Trek 13.2", Movie.NEW_RELEASE);
    	
    	rental = new LinkedHashSet<Rental>();
    	rental.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(3))));
    	
		String expected = 
			"Rental Record for John Smith\n" 
			+ "Your Current frequent renter points are 2";
		assertEquals(expected, customer.showCurrentRenterPoints(rental));
	}

    @Test
    public void testShouldReturnTotalAmountSpentFor1Transaction() throws Exception {
    	customer.checkoutAndPrintStatement(mixedRentals);
    	assertEquals(17.5, customer.getTotalAmount());
    }
    
    @Test
    public void testShouldReturnTotalAmountSpentFor3Transaction() throws Exception {
    	customer.checkoutAndPrintStatement(mixedRentals);
    	customer.checkoutAndPrintStatement(mixedRentals);
    	customer.checkoutAndPrintStatement(mixedRentals);
    	assertEquals(52.5, customer.getTotalAmount());
    }
    
    @Test
    public void testShouldShowDisclaimerRestrictionStatement() throws Exception
    {
    	final Movie starTrek = new Movie("Star Trek 13.2", Movie.NEW_RELEASE);
    	
    	rental = new LinkedHashSet<Rental>();
    	rental.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(3))));
    	
    	String expected = 
			"Rental Record for John Smith\n" 
			+ "  Star Trek 13.2  -  $3.0\n"
			+ "Amount charged is $3.0\n"
			+ "You have a new total of 2 frequent renter points"
    		+ "\nHello John Smith, The New Release Price Movies were restricted to one day rental and amount charged will also reflect the same.";
		assertEquals(expected, customer.checkoutAndPrintStatement(rental));
    }
    
    @Test
    public void testShouldShowDisclaimerRestrictionStatementForCustomerPadma() throws Exception
    {
    	final Movie starTrek = new Movie("Star Trek 13.2", Movie.NEW_RELEASE);
    	customer = new Customer("Padma", "jsmith", "password");
    	rental = new LinkedHashSet<Rental>();
    	rental.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(3))));
    	
    	String expected = 
			"Rental Record for Padma\n" 
			+ "  Star Trek 13.2  -  $3.0\n"
			+ "Amount charged is $3.0\n"
			+ "You have a new total of 2 frequent renter points"
    		+ "\nHello Padma, The New Release Price Movies were restricted to one day rental and amount charged will also reflect the same.";
		assertEquals(expected, customer.checkoutAndPrintStatement(rental));
    }
    
    @Test
    public void testShouldNotShowDisclaimerRestrictionStatementForRegular() throws Exception
    {
    	final Movie starTrek = new Movie("Star Trek 13.2", Movie.REGULAR);
    	
    	rental = new LinkedHashSet<Rental>();
    	rental.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(2))));
    	
    	String expected = 
			"Rental Record for John Smith\n" 
			+ "  Star Trek 13.2  -  $2.0\n"
			+ "Amount charged is $2.0\n"
			+ "You have a new total of 1 frequent renter points";
		assertEquals(expected, customer.checkoutAndPrintStatement(rental));
    }
    
    @Test
    public void testShouldNotShowDisclaimerRestrictionStatementForChildrens() throws Exception
    {
    	final Movie starTrek = new Movie("Star Trek 13.2", Movie.CHILDRENS);
    	
    	rental = new LinkedHashSet<Rental>();
    	rental.add(new Rental(customer, starTrek, Period.of(LocalDate.today(), Duration.ofDays(2))));
    	
    	String expected = 
			"Rental Record for John Smith\n" 
			+ "  Star Trek 13.2  -  $1.5\n"
			+ "Amount charged is $1.5\n"
			+ "You have a new total of 1 frequent renter points";
		assertEquals(expected, customer.checkoutAndPrintStatement(rental));
    }

}
